<?php
/**
 * 定义 GD_FilesUploader 对象
 *
 * @copyright Copyright (c) 2005 - 2008 www.Neten.de
 * @author Peng Zhang (www.neten.de)
 * @package Core
 * @version FilesUploader.php 2007-12-06 18:08:17
 */



/**
 * FLEA_Helper_FilesUploader 实现了一个强大的、可扩展的文件上传助手
 *
 * 
 * 使用方法：
 * <code>
 * FLEA::loadClass('FLEA_Helper_FilesUploader');
 * $f = new FLEA_Helper_FilesUploader();
 * $f->setFileformat(array('jpg','jpge')); // 参数默认值：(array('gif','jpg','jpeg','png','application/octet-stream'))，文件格式&MIME限定
 * $f->setMaxsize(0);				// 参数默认值：(0)，文件大小限制，0 表示无限制，但受php.ini中upload_max_filesize设置影响
 * $f->setOverwrite(0);				// 参数默认值：(0)，是否允许覆盖同名称文件， 0 不允许  1 允许
 * $f->setChangeName(0);			// 参数默认值：(1)，是否改变上传文件的文件名， 0 保持原文件名  1 改变
 * $f->setThumb(1);					// 参数默认值：(0,130,130,"_thumb_")，第一个参数等于 1 则要求产生缩略图，第二和第三个参数是缩略图的宽和高,第四个参数是缩略图前缀
 * if ($f->setSavepath("upload/")){	// 参数默认值：("upload/")，设置并视情况创建上传目录
 *     if (!$f->run('uploadinput')){	// 参数默认值：("uploadinput")，uploadinput是Html页面的<Form>中上传文件的<input>的名字
 *         echo $f->errmsg();			// 这里只能传递最后一个出错的信息，详细的信息在$f->getInfo()中可以得到。
 *     }
 * }else{
 *     echo $f->errmsg();				// 创建目录失败后返回出错信息
 * }
 * echo "<pre>";
 * print_r($f->getInfo());
 * echo "</pre>";
 * </code>
 */


/**
 * 我们上传一个已经存在了的图片文件，一个正常的图片文件，和一个不允许上传的文件，
 * 输出结果如下:
 * The uploaded file is Unallowable!
 * 
 * Array
 * (
 * 	[0] => Array
 * 		(
 * 			[name] => boy.jpg
 * 			[saveName] => boy.jpg
 * 			[size] => 137
 * 			[type] => image/pjpeg
 * 			[error] => File exist already!
 * 		)
 * 
 * 	[1] => Array
 * 		(
 * 			[name] => girl.JPG
 * 			[saveName] => girl.JPG
 * 			[size] => 31
 * 			[type] => image/pjpeg
 * 			[originalHeight] => 450
 * 			[originalWidth] => 600
 * 		)
 * 
 * 	[2] => Array
 * 		(
 * 			[name] => test.wma
 * 			[saveName] => test.wma
 * 			[size] => 971
 * 			[type] => audio/x-ms-wma
 * 			[error] => The uploaded file is Unallowable!
 * 		)
 * 
 * )
 * 
 * 
 * @package Core
 * @author Peng Zhang (www.neten.de)
 * @version 2.0
 */

class GD_FilesUploader{
	var $saveName;						// 保存名
	var $savePath = "upload/";			// 保存路径
	var $fileFormat = array('gif','jpg','jpeg','png','application/octet-stream');// 文件格式&MIME限定
	var $overwrite = 0;					// 覆盖模式
	var $maxSize = 0;					// 文件最大字节
	var $changeName = 1;				// 保存上传文件时，是否改变文件名，0 保持原文件名  1 改变
	var $ext;							// 文件扩展名
	var $thumb = 0;						// 是否生成缩略图
	var $thumbWidth = 130;				// 缩略图宽
	var $thumbHeight = 130;				// 缩略图高
	var $thumbPrefix = "_thumb_";		// 缩略图前缀
	var $errno = 0;						// 错误代号
	var $returnArray= array();			// 所有文件的返回信息
	var $returninfo= array();			// 每个文件返回信息
	var $myName;						// 自定义上传的文件名
	/**
	* 构造函数
	*/
	function GD_FilesUploader() {
	}

	/**
	* 上传文件
	*/
	function run($fileInput){
		if(isset($_FILES[$fileInput])){
			$fileArr = $_FILES[$fileInput];
			if(is_array($fileArr['name'])){//上传同文件域名称多个文件
				for($i = 0; $i < count($fileArr['name']); $i++){
					$ar['tmp_name'] = $fileArr['tmp_name'][$i];
					$ar['name'] = $fileArr['name'][$i];
					$ar['type'] = $fileArr['type'][$i];
					$ar['size'] = $fileArr['size'][$i];
					$ar['error'] = $fileArr['error'][$i];
					$this->getExt($ar['name']);//取得扩展名，赋给$this->ext，下次循环会更新
					$this->setSavename($this->changeName == 1 ? '' : $ar['name']);//设置保存文件名
					if($this->copyfile($ar)){
						$this->returnArray[] =  $this->returninfo;
					}else{
						$this->returninfo['error'] = $this->errmsg();
						$this->returnArray[] =  $this->returninfo;
					}
				}
				return $this->errno ?  false :  true;
			}else{//上传单个文件
				$this->getExt($fileArr['name']);//取得扩展名
				$this->setSavename($this->changeName == 1 ? '' : $fileArr['name']);//设置保存文件名
				if($this->copyfile($fileArr)){
					$this->returnArray[] =  $this->returninfo;
				}else{
					$this->returninfo['error'] = $this->errmsg();
					$this->returnArray[] =  $this->returninfo;
				}
				return $this->errno ?  false :  true;
			}
			return false;
		}else{
			$this->errno = 10;
			return false;
		}
	}

	/**
	* 单个文件上传
	*/
	function copyfile($fileArray){
		$this->returninfo = array();
		// 返回信息
		$this->returninfo['name'] = $fileArray['name'];
		$this->returninfo['saveName'] = $this->saveName;
		$this->returninfo['size'] = number_format( ($fileArray['size'])/1024 , 0, '.', ' ');//以 KB 为单位
		$this->returninfo['type'] = $fileArray['type'];
		// 检查文件格式
		if (!$this->validateFormat()){
			$this->errno = 11;
			return false;
		}
		// 检查目录是否可写
		if(!@is_writable($this->savePath)){
			$this->errno = 12;
			return false;
		}
		// 如果不允许覆盖，检查文件是否已经存在
		if($this->overwrite == 0 && @file_exists($this->savePath.$fileArray['name'])){
			$this->errno = 13;
			return false;
		}
		// 如果有大小限制，检查文件是否超过限制
		if ($this->maxSize != 0 ){
			if ($fileArray["size"] > $this->maxSize){
				$this->errno = 14;
				return false;
			}
		}
		// 文件上传
		if(!@copy($fileArray["tmp_name"], $this->savePath.$this->saveName)){
			$this->errno = $fileArray["error"];
			return false;
		}elseif( $this->thumb ){// 创建缩略图
			$CreateFunction = "imagecreatefrom".($this->ext == 'jpg' ? 'jpeg' : $this->ext);
			$SaveFunction = "image".($this->ext == 'jpg' ? 'jpeg' : $this->ext);
			if (strtolower($CreateFunction) == "imagecreatefromgif" 
				&& !function_exists("imagecreatefromgif")) {
				$this->errno = 16;
				return false;
			} elseif (strtolower($CreateFunction) == "imagecreatefromjpeg" 
				&& !function_exists("imagecreatefromjpeg")) {
				$this->errno = 17;
				return false;
			} elseif (!function_exists($CreateFunction)) {
				$this->errno = 18;
				return false;
			}
				
			$Original = @$CreateFunction($this->savePath.$this->saveName);
			if (!$Original) {$this->errno = 19; return false;}
			$originalHeight = ImageSY($Original);
			$originalWidth = ImageSX($Original);
			$this->returninfo['originalHeight'] = $originalHeight;
			$this->returninfo['originalWidth'] = $originalWidth;
			if (($originalHeight < $this->thumbHeight 
				&& $originalWidth < $this->thumbWidth)) {
				// 如果比期望的缩略图小，那只Copy
				copy($this->savePath.$this->saveName, 
					$this->savePath.$this->thumbPrefix.$this->saveName);
			} else {
				if( $originalWidth > $this->thumbWidth ){// 宽 > 设定宽度
					$thumbWidth = $this->thumbWidth ;
					$thumbHeight = $this->thumbWidth * ( $originalHeight / $originalWidth );
					if($thumbHeight > $this->thumbHeight){// 高 > 设定高度
						$thumbWidth = $this->thumbHeight * ( $thumbWidth / $thumbHeight );
						$thumbHeight = $this->thumbHeight ;
					}
				}elseif( $originalHeight > $this->thumbHeight ){// 高 > 设定高度
					$thumbHeight = $this->thumbHeight ;
					$thumbWidth = $this->thumbHeight * ( $originalWidth / $originalHeight );
					if($thumbWidth > $this->thumbWidth){// 宽 > 设定宽度
						$thumbHeight = $this->thumbWidth * ( $thumbHeight / $thumbWidth );
						$thumbWidth = $this->thumbWidth ;
					}
				}
				if ($thumbWidth == 0) $thumbWidth = 1;
				if ($thumbHeight == 0) $thumbHeight = 1;
				$createdThumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
				if ( !$createdThumb ) {$this->errno = 20; return false;}
				if ( !imagecopyresampled($createdThumb, $Original, 0, 0, 0, 0, 
					$thumbWidth, $thumbHeight, $originalWidth, $originalHeight) )
					{$this->errno = 21; return false;}
				if ( !$SaveFunction($createdThumb, 
					$this->savePath.$this->thumbPrefix.$this->saveName) )
					{$this->errno = 22; return false;}
			}
		}
		// 删除临时文件
		if(!@$this->del($fileArray["tmp_name"])){
			return false;
		}
		return true;
	}

	/**
	* 文件格式检查,MIME检测
	*/
    function validateFormat(){
        if(!is_array($this->fileFormat) 
            || in_array(strtolower($this->ext), $this->fileFormat) 
            || in_array(strtolower($this->returninfo['type']), $this->fileFormat) )
            return true;
        else
            return false;
    }
	/**
	* 获取文件扩展名
	*/
	function getExt($fileName){
		$ext = explode(".", $fileName);
		$ext = $ext[count($ext) - 1];
		$this->ext = strtolower($ext);
	}

	/**
	* 设置上传文件的最大字节限制
	* @param $maxSize 文件大小(bytes) 0:表示无限制
	*/
	function setMaxsize($maxSize = 0){
		$this->maxSize = $maxSize;
	}

	/**
	* 设置文件格式限定
	* @param $fileFormat 文件格式数组
	*/
	function setFileformat($fileFormat){
		if(is_array($fileFormat)){$this->fileFormat = $fileFormat ;}
	}

	/**
	* 设置覆盖模式
	* @param overwrite 覆盖模式 1:允许覆盖 0:禁止覆盖
	*/
	function setOverwrite($overwrite = 0){
		$this->overwrite = $overwrite;
	}

	/**
	* 设置是否改变上传文件的文件名
	* @param changeName  1:改变 0:保持原文件名
	*/
	function setChangeName($changeName = 1){
		$this->changeName = $changeName;
	}

	/**
	* 设置保存路径，如果路径不存在，那就尝试建立文件夹
	* @param $savePath 文件保存路径
	*/
	function setSavepath($savePath = "upload/"){
		//$savePath 要求以 "/" 结尾，若没有 "/"，则补上
		$this->savePath = substr( str_replace("\\","/", $savePath) , -1) == "/" ? $savePath : $savePath."/";
		
		//如果目录不存在，就要建目录，要求目录名称最后没有"/"，要是有的话，以'/'打散为数组的时候，最后将会出现一个空值
		$directoryName = substr($this->savePath, 0, -1);
		$dirNames = explode('/', $directoryName);
		$total = count($dirNames) ;
		$temp = '';
		for($i=0; $i<$total; $i++) {
			$temp .= $dirNames[$i].'/';
			if (!is_dir($temp)) {
				$oldmask = umask(0);
				if (!mkdir($temp, 0777)){
					$this->errno = 23;
					return false;
				}
				umask($oldmask);
			}
		}
		return true;
	}

	/**
	* 设置缩略图
	* @param $thumb = 1 产生缩略图 $thumbWidth,$thumbHeight 是缩略图的宽和高，$thumbPrefix是缩略图前缀
	*/
	function setThumb($thumb = 0, $thumbWidth = 130, $thumbHeight = 130, $thumbPrefix = "_thumb_"){
		$this->thumb = $thumb;
		$this->thumbWidth = $thumbWidth;
		$this->thumbHeight = $thumbHeight;
		$this->thumbPrefix = $thumbPrefix;
	}

	/**
	* 设置文件保存名
	* @saveName 保存名，如果为空，则系统自动生成一个随机的文件名
	*/
	function setSavename($saveName){
		
		if($this->myName){				//如果选择自己命名文件名
			$name=$this->myName;
		}
		else {
			if ($saveName == ''){  // 如果未设置文件名，则生成一个随机文件名
				$name = date('YmdHis')."_".rand(100,999).'.'.$this->ext;
			} else {
				$name = $saveName;
			}
		}
		$this->saveName = $name;
		
	}
	
	/**
	 * 自定义上传到服务器的文件名
	 *
	 * @param string $myname
	 */
	function setMyname($myname){
		$this->myName=$myname;
	}
	/**
	* 删除文件
	* @param $file 所要删除的文件名
	*/
	function del($fileName){
		if(!@unlink($fileName)){
			$this->errno = 15;
			return false;
		}
		return true;
	}

	/**
	* 返回上传文件的信息
	*/
	function getInfo(){
		return $this->returnArray;
	}

	/**
	* 清空上传文件的信息
	*/
	function clearInfo(){
		unset($this->returnArray);
		return true;
	}
	
	/**
	* 得到错误信息
	*/
	function errmsg(){
		$uploadClassError = array(
			0	=>'There is no error, the file uploaded with success. ',
			1	=>'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
			2	=>'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.  ',
			3	=>'The uploaded file was only partially uploaded. ',
			4	=>'No file was uploaded. ',
			6	=>'Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3. ',
			7	=>'Failed to write file to disk. Introduced in PHP 5.1.0. ',
			10	=>'Input name is not unavailable!',
			11	=>'The uploaded file is Unallowable!',
			12	=>'Directory unwritable!',
			13	=>'File exist already!',
			14	=>'File is too big!',
			15	=>'Delete file unsuccessfully!',
			16	=>'Your version of PHP does not appear to have GIF thumbnailing support.',
			17	=>'Your version of PHP does not appear to have JPEG thumbnailing support.',
			18	=>'Your version of PHP does not appear to have pictures thumbnailing support.',
			19	=>'An error occurred while attempting to copy the source image . Your version of php ('.phpversion().') may not have this image type support.',
			20	=>'An error occurred while attempting to create a new image.',
			21	=>'An error occurred while copying the source image to the thumbnail image.',
			22	=>'An error occurred while saving the thumbnail image to the filesystem. Are you sure that PHP has been configured with both read and write access on this folder?',
			23	=>'An error occurred while creat directory:'.$this->savePath.'!',
				);
		if ($this->errno == 0)
			return false;
		else
			return $uploadClassError[$this->errno];
	}
}
?>